home *** CD-ROM | disk | FTP | other *** search
- // -------------------------------------------------------------------------------------
- // ExecMonitor
- // -------------------------------------------------------------------------------------
- // Permission is granted to freely redistribute this source code, and to use fragments
- // of this code in your own applications if you find them to be useful. This class,
- // along with the source code, come with no warranty of any kind, and the user assumes
- // all responsibility for its use.
- // -------------------------------------------------------------------------------------
-
- #import <appkit/appkit.h>
- #import <libc.h>
- #import <stdlib.h>
- #import <c.h>
- #import <errno.h>
- #import <ctype.h>
- #import <math.h>
- #import <sys/param.h>
- #import <sys/types.h>
- #import <sys/time.h>
- #import <sys/wait.h>
- #import <sys/resource.h>
- #import "RemoteCommand.h"
- #import "userInfo.h"
- #import "ExecServer.h"
- #import "ExecScrollText.h"
- #import "ExecMonitor.h"
-
- // -------------------------------------------------------------------------------------
- // misc defines
- #define REMOTE_SERVER_CMD "RemoteRunServer"
-
- // -------------------------------------------------------------------------------------
- // misc defines
- #define X origin.x
- #define Y origin.y
- #define W size.width
- #define H size.height
- #define freeString(X) { if (X) { free((char*)X); X = 0; } }
- #define freeCopy(T,F) { freeString(T); if (F) T = NXCopyStringBuffer(F); }
- #define cpnil (char*)nil
- #define exeBtnTITLE "Execute\nCommand"
-
- // -------------------------------------------------------------------------------------
- // ExecMonitor list of instances
- static id instanceList = (id)nil;
-
- // -------------------------------------------------------------------------------------
- // list of cached user passwords
- typedef struct userPassword_s {
- char *user; // user name
- char *password; // password
- void *next; // pointer to next user
- } userPassword_t;
- static userPassword_t *userList = (userPassword_t*)nil;
-
- // -------------------------------------------------------------------------------------
- @implementation ExecMonitor
-
- // -------------------------------------------------------------------------------------
- // user password
- // -------------------------------------------------------------------------------------
-
- /* find user password */
- + (userPassword_t*)_findUserRcd:(const char*)user
- {
- userPassword_t *u;
- for (u = userList; u && strcmp(user, u->user); u = (userPassword_t*)u->next);
- return u;
- }
-
- /* update user password */
- + (userPassword_t*)_addUser:(const char*)userName password:(const char*)password
- {
- userPassword_t *u;
- if (!XUserVerifyPassword(userName, password)) return (userPassword_t*)nil;
- u = (userPassword_t*)malloc(sizeof(userPassword_t));
- u->user = NXCopyStringBuffer(userName);
- u->password = NXCopyStringBuffer(password?password:"");
- u->next = (void*)userList;
- userList = u;
- return u;
- }
-
- /* find user password */
- + (const char*)findUserPassword:(const char*)user
- {
- userPassword_t *u = [self _findUserRcd:user];
- return u? u->password : (char*)nil;
- }
-
- /* update user password */
- + updateUser:(const char*)user password:(const char*)password
- {
- userPassword_t *u = [self _findUserRcd:user];
- if (u) { if (strcmp(u->password, password)) freeCopy(u->password, password); }
- else [self _addUser:user password:password];
- return self;
- }
-
- /* update user password */
- + removeUserPassword:(const char*)user
- {
- userPassword_t *u = userList, *l = (userPassword_t*)nil;
- for (;u && strcmp(user,u->user); l = u, u = (userPassword_t*)u->next);
- if (u) {
- (l? l->next : userList) = u->next;
- freeString(u->user);
- freeString(u->password);
- free(u);
- }
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // object initialization
- // -------------------------------------------------------------------------------------
-
- /* new exec monitor */
- + newExecHost:(const char*)host server:(const char*)server
- {
- self = [[self alloc] init];
- if (![self setRemoteHost:host server:server]) {
- [self free];
- return (id)nil;
- }
- [self showPanel:self];
- return self;
- }
-
- /* init */
- - init
- {
- NXRect wFrame;
-
- /* instanceList initialization */
- if (!instanceList) instanceList = [[[List alloc] initCount:1] empty];
- [instanceList addObject:self];
-
- /* init super */
- [super init];
- exeUser = (id)nil;
- exePassword = (id)nil;
- exeWindow = (id)nil;
- exeCommandScroll = (id)nil;
-
- /* load nib */
- if (![NXApp loadNibSection:"ExecMonitor.nib" owner:self]) {
- NXLogError("[ExecMonitor] Could not load nib file 'ExecMonitor.nib'");
- [NXApp delayedFree:self];
- return self;
- }
-
- /* spot-check nib loading */
- if (!exeWindow || !exeCommandScroll) {
- NXLogError("[ExecMonitor] 'ExecMonitor.nib' did not load properly");
- [NXApp delayedFree:self];
- return self;
- }
-
- /* init vars */
- saveFileName = (char*)nil;
- useRunServer = YES;
- cmdInProcess = NO;
- shutDown = NO;
- exeRunServer = (id)nil;
-
- /* set user values if specified */
- if (exeUser) [exeUser setStringValue:""];
- if (exePassword) [exePassword setStringValue:""];
-
- /* init panel */
- [exeExecute setTitle:exeBtnTITLE];
- [exeCommandScroll clearScrollText];
- [exeControlBox setBorderType:NX_NOBORDER];
- [exeWindow setDelegate:self];
- [exeWindow setFreeWhenClosed:NO];
- [exeWindow getFrame:&wFrame];
- minWinSize = wFrame.size;
-
- return self;
- }
-
- /* free */
- - _free:sender { return [self free]; }
- - free
- {
- shutDown = YES;
- if (cmdInProcess) { // loop until command has completed
- [self exeExecute:(id)nil];
- [self perform:@selector(_free:) with:self afterDelay:500 cancelPrevious:YES];
- return (id)nil;
- }
- [exeWindow free];
- [instanceList removeObject:self]; // make sure 'self' is removed
- return [super free];
- }
-
- // -------------------------------------------------------------------------------------
- // run arguments
-
- /* set remote host (start server if necessary) */
- - setRemoteHost:(const char*)host server:(const char*)server
- {
- char cmd[MAXPATHLEN + 1], title[256];
-
- /* check for already set */
- if (exeRunServer) {
- NXLogError("[ExecMonitor] ExecServer is already running");
- return (id)nil;
- }
-
- /* instantiate ExecServer object */
- exeRunServer = (host && *host)? [[ExecServer alloc] init] : (id)nil;
- if (!exeRunServer) {
- NXLogError("[ExecMonitor] Could not create ExecServer (no host specified)");
- return (id)nil;
- }
-
- /* set attributes */
- [exeRunServer setMainAppPath:XAppPath()];
- [exeRunServer setMainAppServerName:[NXApp appServerName] host:[NXApp appServerHost]];
- [exeRunServer setRemoteHost:host];
- if (server && *server) [exeRunServer setRemoteServerName:server];
- sprintf(cmd, "%s/%s", XAppPath(), REMOTE_SERVER_CMD);
- if (![exeRunServer setServerCommandName:cmd]) {
- NXLogError("[ExecMonitor] Unable to set ExecServer command to %s", cmd);
- exeRunServer = (id)nil;
- return (id)nil;
- }
-
- /* start server */
- if (![exeRunServer startServer]) {
- NXLogError("[ExecMonitor] Could not connect to RemoteRunServer");
- exeRunServer = (id)nil;
- return (id)nil;
- }
-
- /* set window title */
- sprintf(title, "ExecMonitor: %s (%s)",
- [exeRunServer remoteHost], [exeRunServer remoteServerName]);
- [exeWindow setTitle:title];
-
- return self;
- }
-
- /* show ExecMonitor panel */
- - showPanel:sender
- {
- return [exeWindow makeKeyAndOrderFront:(id)nil];
- }
-
- // -------------------------------------------------------------------------------------
- // command execution
- // -------------------------------------------------------------------------------------
-
- /* print messages */
- - _printCompletion:(BOOL)isError:(char*)fmt, ...
- {
- char *h = isError?">>>>>>>>>>":"----------", *t = isError?"<<<<<<<<<<":"----------";
- va_list args;
-
- /* message color and header */
- if (isError) [exeShellScroll setTextAttributeColor:NX_COLORRED];
- else [exeShellScroll setTextAttributeGray:NX_DKGRAY];
- [exeShellScroll textPrintf:"\n%s ", h];
-
- /* message */
- va_start(args, fmt);
- [exeShellScroll textPrintf:fmt args:args];
- va_end(args);
-
- /* message trailer and reset gray */
- [exeShellScroll textPrintf:" %s\n\n", t];
- [exeShellScroll setTextAttributeGray:textGray];
-
- /* return error condition */
- return isError? (id)nil : self;
-
- }
-
- /* execute Server command */
- - exeExecute:sender
- {
- int commandLen;
- char *cmdStr, *user, *pass;
-
- /* check for no run server */
- if (!exeRunServer) { NXBeep(); return (id)nil; }
-
- /* check for "STOP" */
- if (cmdInProcess) {
- if (!strcmp([exeExecute icon], "Stop")) {
- if (useRunServer) [exeRunServer terminateCommand:execId];
- else [exeShellScroll terminateCommand];
- [exeExecute setIcon:"Kill"];
- } else {
- if (useRunServer) [exeRunServer killCommand:execId];
- else [exeShellScroll killCommand];
- }
- return self;
- }
- if (!sender) return (id)nil;
-
- /* exit if shutdown in progress */
- if (shutDown) return (id)nil;
-
- /* get user */
- user = exeUser? (char*)[exeUser stringValue] : (char*)nil;
- if (!user || !*user) user = (char*)[NXApp appUserName];
-
- /* get password (if needed) */
- if (!XIsCurrentUser(user)) {
- pass = exePassword? (char*)[exePassword stringValue] : "";
- if ([exeRunServer needUserPassword:user] && !XUserVerifyPassword(user, pass)) {
- [[self class] removeUserPassword:user];
- return [self _printCompletion:1:"User password not valid"];
- }
- [[self class] updateUser:user password:pass];
- }
-
- /* setup command */
- commandLen = [[exeCommandScroll docView] textLength] + 1;
- cmdStr = (char*)malloc(commandLen + 1);
- [[exeCommandScroll docView] getSubstring:cmdStr start:0 length:commandLen];
- strcat(cmdStr, "\n");
-
- /* print command info */
- [exeShellScroll setTextAttributeGray:NX_DKGRAY];
- [exeShellScroll textPrintf:"\n---------- Executing Command ----------\n"];
- [exeShellScroll textPrintf:"%s", cmdStr];
- [exeShellScroll textPrintf: "---------------------------------------\n\n"];
- [exeShellScroll setTextAttributeGray:textGray];
-
- /* run command */
- if (useRunServer) {
- execId = [exeRunServer runCommand:cmdStr
- withUser:user:[[self class] findUserPassword:user]
- forClient:exeShellScroll
- killOnError:YES];
- } else {
- execId = (execHandle_t)[exeShellScroll runCommand:cmdStr];
- }
-
- /* free command */
- free(cmdStr);
-
- /* check to see if command actually started running */
- if (!execId) return [self _printCompletion:1:"Command failed to start"];
-
- /* change button */
- cmdInProcess = YES;
- [exeExecute setIconPosition:NX_ICONONLY];
- [exeExecute setIcon:"Stop"];
-
- return self;
- }
-
- /* call-back from shell command (main thread) */
- - commandDidComplete:shellId withError:(int)theError
- {
-
- /* check for completion status */
- if (!theError) { // successful
- [self _printCompletion:0:"completed normally"];
- } else {
- char *desc = [ExecServer errorDesc:theError];
- if (desc) [self _printCompletion:1:"%s",desc];
- else [self _printCompletion:1:"Terminated with exit(%d)",theError];
- }
-
- /* remove user if password is bad */
- if ((theError == RSRV_BADPASSWD) && exeUser) {
- [ExecMonitor removeUserPassword:[exeUser stringValue]];
- }
-
- /* reset execution button */
- [exeExecute setEnabled:YES];
- [exeExecute setIconPosition:NX_TITLEONLY];
- [exeExecute setTitle:exeBtnTITLE];
- cmdInProcess = NO;
- execId = (execHandle_t)nil;
-
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // Terminal invoke
- // -------------------------------------------------------------------------------------
-
- /* invoke command in Terminal window */
- + terminalCommand:(const char*)cmd title:(const char*)title
- {
- Speaker *speaker;
- port_t terminalPort;
-
- /* can't find Terminal */
- if (!(terminalPort = NXPortFromName("Terminal", NULL))) return (id)nil;
-
- /* launch Terminal */
- [NXApp deactivateSelf];
- creat("/tmp/.reallyignorethis.term", 0444);
- [[Application workspace] openFile:"/tmp/.reallyignorethis.term"
- fromImage:(id)nil at:(NXPoint*)nil inView:(id)nil];
-
- /* run command */
- speaker = [NXApp appSpeaker];
- [speaker setSendPort: terminalPort];
- [speaker selectorRPC:"runCommand:usingShell:inFolder:windowTitle:closeOnExit:"
- paramTypes: "cccci", cmd, "", "", title, NO];
-
- return self;
-
- }
-
- // -------------------------------------------------------------------------------------
- // outlets
- // -------------------------------------------------------------------------------------
-
- - setExeShellScroll:anObject
- {
- exeShellScroll = [[ExecScrollText newExecScrollText:anObject] clearScrollText];
- [exeShellScroll setDelegate:self];
- textFont = [[exeShellScroll docView] font];
- textGray = [[exeShellScroll docView] textGray];
- [exeShellScroll setTab:[textFont getWidthOf:" "] count:10];
- [exeShellScroll textPrintf:"\n"]; // this forces the scroll view to initialize
- [exeShellScroll clearScrollText];
- return self;
- }
-
- - setExeCommandScroll:anObject
- {
- exeCommandScroll = [[ExecScrollText newExecScrollText:anObject] clearScrollText];
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // first responder methods
- // -------------------------------------------------------------------------------------
-
- /* save error handler */
- - (BOOL)attemptOverwrite:(const char*)fileName
- {
- NXLogError("[ExecMonitor] Unable to save %s", fileName);
- return NO;
- }
-
- /* save contents of text view */
- - saveAs:sender
- {
- char *temp;
- id savePanel = [SavePanel new];
-
- /* set up save panel */
- [savePanel setTitle:"Save Command Output"];
- [savePanel setPrompt:"File:"];
- [savePanel setRequiredFileType:""];
- [savePanel setDirectory:(saveFileName?saveFileName:[NXApp appUserHome])];
-
- /* get file name to save */
- if (![savePanel runModalForDirectory:[NXApp appUserHome] file:""]) return self;
- if (!(temp = (char*)[savePanel filename])) return self;
- freeString(saveFileName);
- saveFileName = NXCopyStringBuffer(temp);
-
- return [self save:sender];
- }
-
- /* save contents of text view */
- - save:sender
- {
- if (!saveFileName) return [self saveAs:sender];
- [[exeShellScroll docView] saveRTFDTo:saveFileName removeBackup:NO errorHandler:self];
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // window close
- // -------------------------------------------------------------------------------------
-
- /* close all windows */
- + closeAllWindows
- {
- if (instanceList) [instanceList makeObjectsPerform:@selector(closeWindow:) with:self];
- return self;
- }
-
- /* shut down */
- - closeWindow:sender
- {
- return [exeWindow performClose:self];
- }
-
- // -------------------------------------------------------------------------------------
- // window delegate methods
- // -------------------------------------------------------------------------------------
-
- - windowWillClose:windowId
- {
- if (cmdInProcess) return (id)nil;
- [instanceList removeObject:self];
- return [NXApp delayedFree:self];
- }
-
- - windowWillResize:windowId toSize:(NXSize*)newSize
- {
- if (newSize->width < minWinSize.width ) newSize->width = minWinSize.width;
- if (newSize->height < minWinSize.height) newSize->height = minWinSize.height;
- return self;
- }
-
- @end
-